﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms;
using HalconDotNet;
using Tensorflow;
using Tensorflow.NumPy;
using static Tensorflow.Binding;
using static Tensorflow.KerasApi;
using System.IO;
using System.Drawing;
using System.Diagnostics;
using System.Threading;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using OpenCL;
using OpenCL.Net;
using System.Windows.Media.Media3D;
using static System.Runtime.CompilerServices.RuntimeHelpers;
using static HDF.PInvoke.H5T;
using System.Collections;
using System.Security.Policy;
using Tensorflow.Keras.Engine;
using Tensorflow.Keras.Layers;
using Tensorflow.Keras.ArgsDefinition;
using Tensorflow.Keras;

namespace WpfApp3
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        string path;
        //文件夹选着
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //创建一个选择文件夹的对话框
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();

            //调用ShowDialog()方法显示该对话框，该方法的返回值代表用户是否点击了确定按钮
            if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.Cancel)
            {
                path = dialog.SelectedPath.Trim();
                数据显示.Text = path;
                PrintAllImageFiles(path);
                foreach (var item in 路径集合)
                {
                    数据显示.Text = 数据显示.Text + '\n' + item;
                }
            }
            else
            {
                数据显示.Text = "取消了路径选着";
                //点击了取消
            }

        }
        //数据路径集合
        public List<string> 路径集合 = new List<string>();
        private void PrintAllImageFiles(string folderPath)
        {
            路径集合.Clear();
            //检查文件是否存在
            if (Directory.Exists(folderPath))
            {
                string[] files = Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories);
                // 检查文件是否为图片文件
                foreach (string file in files)
                {
                    // 获取文件扩展名
                    string fileExtension = System.IO.Path.GetExtension(file)?.ToLower();
                    数据显示.Text = fileExtension;
                    // 检查文件是否为图片文件
                    if (".jpeg" == fileExtension)
                    {
                        路径集合.Add(file);
                        // 打印图片文件路径
                        数据显示.Text = file;
                    }
                }
            }
            else
            {
                数据显示.Text = "路径存在错误";
            }
        }
        //训练测试
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {

        }
        //部署测试
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {

        }
        OpenCLImageProcessor openCLImageProcessor = new OpenCLImageProcessor(4090, 4096);
        /// <summary>
        /// 数据预处理
        /// </summary>
        /// <param name="pathlist">路径集合</param>
        private void datapreprocessing(List<string> pathlist)
        {
            
            //openCLImageProcessor.InitializeOpenCL();
            foreach (var item in pathlist)
            {
                Stopwatch stopwatch = new Stopwatch();
                // 开始计时
                
                //Bitmap res24;
                HImage image = new HImage();
                image.ReadImage(item);
                显示图片.HalconWindow.DispObj(image);
                数据转化(image);
                //数据显示.Text = res24.ToString();
                stopwatch.Start();
                image.GetImagePointer3(out IntPtr pointerRed, out IntPtr pointerGreen, out IntPtr pointerBlue, out string type, out int w, out int h);
                float[,,] hostArray = openCLImageProcessor.ProcessImage(pointerRed, pointerGreen, pointerBlue);
                var tens = tf.constant(hostArray);
                
                stopwatch.Stop();
                // 输出执行时间
                Console.WriteLine($"执行时间1: {stopwatch.ElapsedMilliseconds} 毫秒");
                数据显示.Text = stopwatch.ElapsedMilliseconds.ToString() + " 毫秒\n";
            }
        }
        /// <summary>
        /// 构建模型
        /// </summary>
        private void model()
        {

        }
        /// <summary>
        /// 数据预处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            datapreprocessing(路径集合);
           //openCLImageProcessor.Dispose();
        }
        int h = 0;
        // private static Queue<int> sharedQueue = new Queue<int>();
        /// <summary>
        /// 数据转化
        /// </summary>
        /// <param name="image">halcon图片</param>
        ///<param name="res24">bitmap图片</param>
        private void 数据转化(HImage image)
        {

            Stopwatch stopwatch = new Stopwatch();
            // 开始计时
            stopwatch.Start();
            HTuple width, height;
            image.GetImageSize(out width, out height);
            byte[] byteArray = new byte[width * height * 3];
            image.GetImagePointer3(out IntPtr pointerRed, out IntPtr pointerGreen, out IntPtr pointerBlue, out string type, out int w, out int h);
            Marshal.Copy(pointerRed, byteArray, 0, width * height);
            Marshal.Copy(pointerGreen, byteArray, width * height, width * height);
            Marshal.Copy(pointerBlue, byteArray, width * height * 2, width * height);
            float[] greenFloats = byteArray.Select(b => b / 255.0f).ToArray();
            var tens = tf.constant(greenFloats);
            tens = tf.reshape(tens, new long[] { width, height, 3 }); // 调整为三维张量
            Console.WriteLine($"----------------");
            //print(tens);
            //print(tens[new Slice(0, 1), new Slice(3200, 4090, 5)]);
            stopwatch.Stop();
            // 输出执行时间
            Console.WriteLine($"执行时间2-----数据转化: {stopwatch.ElapsedMilliseconds} 毫秒");
            数据显示.Text = stopwatch.ElapsedMilliseconds.ToString() + " 毫秒\n";
            Console.WriteLine($"----------------");
            //        执行时间: 1972 毫秒
            //----------------
            //----------------
            //执行时间: 1650 毫秒
            //----------------
            //----------------
            //执行时间: 1598 毫秒


            //时间优化
           // Stopwatch stopwatch = new Stopwatch();
            // 开始计时
            stopwatch.Start();
           // HTuple width, height;
            //image.GetImageSize(out width, out height);

           // image.GetImagePointer3(out IntPtr pointerRed, out IntPtr pointerGreen, out IntPtr pointerBlue, out string type, out int w, out int h);
            double[,,] byteArray1 = new double[w, h, 3];
            byte[] redArray = new byte[w * h];
            byte[] greenArray = new byte[w * h];
            byte[] blueArray = new byte[w * h];
            Marshal.Copy(pointerRed, redArray, 0, w * h);
            Marshal.Copy(pointerGreen, greenArray, 0, w * h);
            Marshal.Copy(pointerBlue, blueArray, 0, w * h);
            for (int y = 0; y < w; y++)
            {
                for (int x = 0; x < h; x++)
                {
                    byteArray1[y, x, 0] = redArray[y * w + x] / 255.0;       // 红色通道
                    byteArray1[y, x, 1] = greenArray[y * w + x] / 255.0;     // 绿色通道
                    byteArray1[y, x, 2] = blueArray[y * w + x] / 255.0;      // 蓝色通道
                }
            }
            var tens1 = tf.constant(byteArray);
            //print(tens);
            //print(tens[new Slice(0, 1), new Slice(3200, 4090, 5)]);
            stopwatch.Stop();
            // 输出执行时间
            Console.WriteLine($"执行时间3: {stopwatch.ElapsedMilliseconds} 毫秒");
            数据显示.Text = stopwatch.ElapsedMilliseconds.ToString() + " 毫秒\n";
            //        执行时间: 891 毫秒
            //执行时间: 958 毫秒
            //执行时间: 927 毫秒

            /*
            Stopwatch stopwatch = new Stopwatch();
            // 开始计时

            HTuple width, height;
            image.GetImageSize(out width, out height);
            //float[,,] byteArray = new float[width, height, 3];
            //GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
            //IntPtr byteArrayPtr = pinnedArray.AddrOfPinnedObject();
            image.GetImagePointer3(out IntPtr pointerRed, out IntPtr pointerGreen, out IntPtr pointerBlue, out string type, out int w, out int h);
            // 计算每个通道的大小
            int size = w * h;
            // 创建 byte 数组来存储每个通道的数据
            byte[] redBytes = new byte[size];
            //GCHandle pinnedArray1 = GCHandle.Alloc(redBytes, GCHandleType.Pinned);
            byte[] greenBytes = new byte[size];
            byte[] blueBytes = new byte[size];

            // 将指针数据复制到 byte 数组中
            Marshal.Copy(pointerRed, redBytes, 0, size);
            Marshal.Copy(pointerGreen, greenBytes, 0, size);
            Marshal.Copy(pointerBlue, blueBytes, 0, size);
            // 将 byte[] 转换为 float[] 并归一化到 [0, 1] 范围
            float[] redFloats = redBytes.Select(b => b / 255.0f).ToArray();
            GCHandle pinnedArray1 = GCHandle.Alloc(redFloats, GCHandleType.Pinned);
            float[] greenFloats = greenBytes.Select(b => b / 255.0f).ToArray();
            GCHandle pinnedArray2 = GCHandle.Alloc(greenFloats, GCHandleType.Pinned);
            float[] blueFloats = blueBytes.Select(b => b / 255.0f).ToArray();
            GCHandle pinnedArray3 = GCHandle.Alloc(blueFloats, GCHandleType.Pinned);

            stopwatch.Start();
            unsafe
            {
                ErrorCode errorCode;
                // 获取平台数量
                Platform[] platforms = Cl.GetPlatformIDs(out _);
                // 选择第一个平台（通常这样做，但您可以根据需要选择）
                Platform platform = platforms[1];
                // 获取设备数量
                Device[] vb = Cl.GetDeviceIDs(platform, DeviceType.Gpu, out _);
                // Cl.get(); // 获取可用的 OpenCL 设备
                // 创建上下文 ContextProperty[] properties
                // 获取平台句柄
                Context context = Cl.CreateContext(null, 1, vb, ContextErrorCallback, IntPtr.Zero, out errorCode);
                if (errorCode != ErrorCode.Success)
                {
                    Console.WriteLine("Failed to create context.");
                    return;
                }
                // 创建命令队列  CommandQueue CreateCommandQueue(Context context, Device device, CommandQueueProperties properties, out ErrorCode error)
                CommandQueue commandQueue = Cl.CreateCommandQueue(context, vb[0], CommandQueueProperties.None, out errorCode);
                if (errorCode != ErrorCode.Success)
                {
                    Console.WriteLine("Failed to create command queue.");
                    return;
                }

                // 假设我们要处理1024个浮点数
                int numElements = w * h;
                var memObjectRed = Cl.CreateBuffer(context, MemFlags.ReadWrite, new IntPtr(numElements * sizeof(byte)), out errorCode); // 创建红色通道内存对象
                var memObjectGreen = Cl.CreateBuffer(context, MemFlags.ReadWrite, new IntPtr(numElements * sizeof(byte)), out errorCode);  // 创建绿色通道内存对象
                var memObjectBlue = Cl.CreateBuffer(context, MemFlags.ReadWrite, new IntPtr(numElements * sizeof(byte)), out errorCode);  // 创建蓝色通道内存对象
                var memObjectOutput = Cl.CreateBuffer(context, MemFlags.WriteOnly, new IntPtr(numElements* 3 * sizeof(float)), out errorCode); // 创建输出内存对象
                Cl.EnqueueWriteBuffer(commandQueue, memObjectRed, Bool.True, IntPtr.Zero, new IntPtr(numElements * sizeof(byte)), pointerRed, 0, null, out var writeEvent);
                Cl.EnqueueWriteBuffer(commandQueue, memObjectGreen, Bool.True, IntPtr.Zero, new IntPtr(numElements * sizeof(byte)), pointerGreen, 0, null, out var writeEvent1);
                Cl.EnqueueWriteBuffer(commandQueue, memObjectBlue, Bool.True, IntPtr.Zero, new IntPtr(numElements * sizeof(byte)), pointerBlue, 0, null, out var writeEvent2);
                Cl.EnqueueReadBuffer(commandQueue, memObjectBlue, Bool.True, IntPtr.Zero, new IntPtr(numElements * sizeof(byte)), pinnedArray1.AddrOfPinnedObject(), 0, null, out var writeEvent3);
                if (errorCode != ErrorCode.Success)
                {
                    Console.WriteLine("Failed to create buffer object.");
                    return;
                }
                C
                // 创建程序对象
                Program program = Cl.CreateProgramWithSource(context, 1, new[] { source }, null, out errorCode);
                if (errorCode != ErrorCode.Success)
                {
                    Console.WriteLine("Failed to create program object1.");
                    return;
                }
                InfoBuffer vbf = Cl.GetProgramInfo(program, ProgramInfo.ReferenceCount, out errorCode);
                if (errorCode != ErrorCode.Success)
                {
                    Console.WriteLine("Failed to create kernel object.4");
                    return;
                }
                // 构建程序   ErrorCode BuildProgram(Program program, uint numDevices, Device[] deviceList, string options, ProgramNotify pfnNotify, IntPtr userData)
                errorCode = Cl.BuildProgram(program, 1, vb, null, null, IntPtr.Zero);
                if (errorCode != ErrorCode.Success)
                {
                    // 获取构建日志
                    InfoBuffer buildLog = Cl.GetProgramBuildInfo(program, vb[0], ProgramBuildInfo.Log, out ErrorCode logError);
                    if (logError == ErrorCode.Success)
                    {
                        Console.WriteLine("Build Log:BuildProgram");
                        Console.WriteLine(buildLog.ToString());
                    }
                    else
                    {
                        Console.WriteLine("Failed to get build log.");
                    }

                    Console.WriteLine("Failed to build program.");
                    return;
                }
                // 获取内核对象
                Kernel kernel = Cl.CreateKernel(program, "vecAdd", out errorCode);
                if (errorCode != ErrorCode.Success)
                {
                    Console.WriteLine("Failed to create kernel object.3");
                    return;
                }
                // 设置内核参数
                Cl.SetKernelArg(kernel, 0, memObjectRed);
                Cl.SetKernelArg(kernel, 1, memObjectGreen);
                Cl.SetKernelArg(kernel, 2, memObjectBlue);
                Cl.SetKernelArg(kernel, 3, memObjectOutput);
                Cl.SetKernelArg(kernel, 4, w);
                Cl.SetKernelArg(kernel, 5, h);
                // 设置执行配置
                IntPtr maxWorkGroupSize = Cl.GetDeviceInfo(vb[0], DeviceInfo.MaxWorkGroupSize, out errorCode).CastTo<IntPtr>();
                Console.WriteLine($"Max Work Group Size: {maxWorkGroupSize}");
                // 设置工作组大小（localWorkSize）
                int localSizeX = 16; // 每个工作组在横坐标方向的大小
                int localSizeY = 32; // 每个工作组在纵坐标方向的大小
                int globalSizeX = (w + localSizeX - 1) / localSizeX * localSizeX; // 向上取整
                int globalSizeY = (h + localSizeY - 1) / localSizeY * localSizeY; // 向上取整
                // 设置执行配置
                IntPtr[] localWorkSize = new IntPtr[] { (IntPtr)32, (IntPtr)32};
                IntPtr[] globalWorkSize = new IntPtr[] { (IntPtr)3520, (IntPtr)4096 };
                // 执行内核
                errorCode = Cl.EnqueueNDRangeKernel(commandQueue, kernel, 2, null, globalWorkSize, localWorkSize, 0, null, out OpenCL.Net.Event kernelEvent);
                if (errorCode != ErrorCode.Success)
                {
                    // 获取构建日志
                    InfoBuffer buildLog = Cl.GetProgramBuildInfo(program, vb[0], ProgramBuildInfo.Log, out ErrorCode logError);
                    if (logError == ErrorCode.Success)
                    {
                        Console.WriteLine("Build Log:EnqueueNDRangeKernel");
                        Console.WriteLine(buildLog.ToString());
                    }
                    else
                    {
                        Console.WriteLine("Failed to get build log.");
                    }

                    Console.WriteLine("Failed to build program.");
                    return;
                }
                // 等待内核执行完成
                Cl.WaitForEvents(1, new[] { kernelEvent });
                // 读取数据回主机
                float[] hostArray = new float[numElements*3];
                GCHandle pinnedArray = GCHandle.Alloc(hostArray, GCHandleType.Pinned);
                errorCode = Cl.EnqueueReadBuffer(commandQueue, memObjectOutput, Bool.True, IntPtr.Zero, new IntPtr(numElements*3), pinnedArray.AddrOfPinnedObject(), 0, null, out OpenCL.Net.Event readEvent);
                if (errorCode != ErrorCode.Success)
                {
                    // 获取构建日志
                    InfoBuffer buildLog = Cl.GetProgramBuildInfo(program, vb[0], ProgramBuildInfo.Log, out ErrorCode logError);
                    if (logError == ErrorCode.Success)
                    {
                        Console.WriteLine("Build Log:EnqueueReadBuffer");
                        Console.WriteLine(buildLog.ToString());
                    }
                    else
                    {
                        Console.WriteLine("Failed to get build log.");
                    }

                    Console.WriteLine("Failed to build program---3.");
                    return;
                }
                pinnedArray.Free();
                // 释放资源
                Cl.ReleaseKernel(kernel);
                Cl.ReleaseProgram(program);
                Cl.ReleaseMemObject(memObjectOutput);
                Cl.ReleaseCommandQueue(commandQueue);
                Cl.ReleaseContext(context);

                //var shape = new TensorShape(new long[] { height, width, 3 });
                //var tens = tf.constant(hostArray, shape: shape);
                // 假设 floatArray 是一个一维数组，大小为 height * width * 3
                var tens = tf.constant(hostArray); // 创建一维张量
                tens = tf.reshape(tens, new long[] { width, height, 3 }); // 调整为三维张量
                //Console.WriteLine($"----------------");
               print(tens);
                //Console.WriteLine($"----------------");
                //print(tens[new Slice(0, 1), new Slice(3200, 4090, 5)]);
                Console.WriteLine($"执行时间: {stopwatch.ElapsedMilliseconds} 毫秒{type}");
                数据显示.Text = stopwatch.ElapsedMilliseconds.ToString() + " 毫秒\n";

            }
            // 输出执行时间
            */
            /*
            // Initialize Stopwatch for performance measurement
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            // Get image data pointers
            image.GetImagePointer3(out IntPtr pointerRed, out IntPtr pointerGreen, out IntPtr pointerBlue, out string type, out int w, out int h);
            int numElements = w * h;

            // Initialize OpenCL
            ErrorCode errorCode;
            Platform[] platforms = Cl.GetPlatformIDs(out errorCode);
            if (errorCode != ErrorCode.Success || platforms.Length == 0)
            {
                Console.WriteLine("Failed to get OpenCL platforms.");
                return;
            }

            // Select the first platform (usually the default)
            Platform platform = platforms[0];

            // Get GPU device
            Device[] devices = Cl.GetDeviceIDs(platform, DeviceType.Gpu, out errorCode);
            if (errorCode != ErrorCode.Success || devices.Length == 0)
            {
                Console.WriteLine("Failed to get GPU devices.");
                return;
            }
            Device device = devices[0];

            // Create OpenCL context
            Context context = Cl.CreateContext(null, 1, new[] { device }, ContextErrorCallback, IntPtr.Zero, out errorCode);
            if (errorCode != ErrorCode.Success)
            {
                Console.WriteLine("Failed to create OpenCL context.");
                return;
            }

            // Create command queue
            CommandQueue commandQueue = Cl.CreateCommandQueue(context, device, CommandQueueProperties.None, out errorCode);
            if (errorCode != ErrorCode.Success)
            {
                Console.WriteLine("Failed to create command queue.");
                return;
            }

            // Create OpenCL buffers for input and output
            var memObjectRed = Cl.CreateBuffer(context, MemFlags.ReadOnly, new IntPtr(numElements * sizeof(byte)), out errorCode);
            var memObjectGreen = Cl.CreateBuffer(context, MemFlags.ReadOnly, new IntPtr(numElements * sizeof(byte)), out errorCode);
            var memObjectBlue = Cl.CreateBuffer(context, MemFlags.ReadOnly, new IntPtr(numElements * sizeof(byte)), out errorCode);
            var memObjectOutput = Cl.CreateBuffer(context, MemFlags.WriteOnly, new IntPtr(numElements * 3 * sizeof(float)), out errorCode);

            // Write data to OpenCL buffers
            Cl.EnqueueWriteBuffer(commandQueue, memObjectRed, Bool.True, IntPtr.Zero, new IntPtr(numElements * sizeof(byte)), pointerRed, 0, null, out var writeEvent);
            Cl.EnqueueWriteBuffer(commandQueue, memObjectGreen, Bool.True, IntPtr.Zero, new IntPtr(numElements * sizeof(byte)), pointerGreen, 0, null, out var writeEvent1);
            Cl.EnqueueWriteBuffer(commandQueue, memObjectBlue, Bool.True, IntPtr.Zero, new IntPtr(numElements * sizeof(byte)), pointerBlue, 0, null, out var writeEvent2);

            // Load and build OpenCL program
            string kernelSource = @"
        __kernel void vecAdd(__global const uchar* red, __global const uchar* green, __global const uchar* blue,
                             __global float* output, int width, int height) {
            int x = get_global_id(0);
            int y = get_global_id(1);
            int index = y * width + x;
            output[index * 3] = red[index] / 255.0f;    // Normalize red
            output[index * 3 + 1] = green[index] / 255.0f; // Normalize green
            output[index * 3 + 2] = blue[index] / 255.0f;  // Normalize blue
        }";
            Program program = Cl.CreateProgramWithSource(context, 1, new[] { kernelSource }, null, out errorCode);
            errorCode = Cl.BuildProgram(program, 1, new[] { device }, null, null, IntPtr.Zero);
            if (errorCode != ErrorCode.Success)
            {
                Console.WriteLine("Failed to build OpenCL program.");
                return;
            }

            // Create kernel
            Kernel kernel = Cl.CreateKernel(program, "vecAdd", out errorCode);
            if (errorCode != ErrorCode.Success)
            {
                Console.WriteLine("Failed to create kernel.");
                return;
            }

            // Set kernel arguments
            Cl.SetKernelArg(kernel, 0, memObjectRed);
            Cl.SetKernelArg(kernel, 1, memObjectGreen);
            Cl.SetKernelArg(kernel, 2, memObjectBlue);
            Cl.SetKernelArg(kernel, 3, memObjectOutput);
            Cl.SetKernelArg(kernel, 4, w);
            Cl.SetKernelArg(kernel, 5, h);

            // Execute kernel
            IntPtr[] globalWorkSize = new IntPtr[] { (IntPtr)(w), (IntPtr)(h)};
            IntPtr[] localWorkSize = new IntPtr[] { (IntPtr)2, (IntPtr)2 }; // Adjust based on GPU capabilities
            errorCode = Cl.EnqueueNDRangeKernel(commandQueue, kernel, 2, null, globalWorkSize, localWorkSize, 0, null, out var kernelEvent);
            if (errorCode != ErrorCode.Success)
            {
                Console.WriteLine("Failed to execute kernel.");
                return;
            }
            // Wait for kernel to finish
            Cl.WaitForEvents(1, new[] { kernelEvent });
            //// Read output data back to host
            //float[] hostArray = new float[numElements * 3];
            //GCHandle pinnedArray = GCHandle.Alloc(hostArray, GCHandleType.Pinned);
            // 创建一个三维数组来存储输出数据
            float[,,] hostArray = new float[h, w, 3]; // 高度 x 宽度 x 通道 (RGB)
            // 固定三维数组的内存
            GCHandle pinnedArray = GCHandle.Alloc(hostArray, GCHandleType.Pinned);
            errorCode = Cl.EnqueueReadBuffer(commandQueue, memObjectOutput, Bool.True, IntPtr.Zero, new IntPtr(numElements * 3 * sizeof(float)), pinnedArray.AddrOfPinnedObject(), 0, null, out var readEvent);
            pinnedArray.Free();
            // Release OpenCL resources
            Cl.ReleaseMemObject(memObjectRed);
            Cl.ReleaseMemObject(memObjectGreen);
            Cl.ReleaseMemObject(memObjectBlue);
            Cl.ReleaseMemObject(memObjectOutput);
            Cl.ReleaseKernel(kernel);
            Cl.ReleaseProgram(program);
            Cl.ReleaseCommandQueue(commandQueue);
            Cl.ReleaseContext(context);
            var tens = tf.constant(hostArray); // 创建一维张量
            print(tens);
            // Stop stopwatch and print elapsed time
            stopwatch.Stop();
            Console.WriteLine($"Processing completed in {stopwatch.ElapsedMilliseconds} ms.");
            */
            //  500ms
        }
        static Sequential CreateModel()
        {
            // 创建 SequentialArgs 对象
            var sequentialArgs = new SequentialArgs();
            // 创建 Sequential 模型并传入 SequentialArgs
            var model = new Sequential(sequentialArgs);
          
            return model;
        }

        private void ContextErrorCallback(string errInfo, byte[] data, IntPtr cb, IntPtr userData)
        {
            Console.WriteLine("OpenCL Context Error: " + errInfo);
        }



    }

    public class OpenCLImageProcessor : IDisposable
    {
        private Context _context;
        private CommandQueue _commandQueue;
        private IMem _memObjectRed;
        private IMem _memObjectGreen;
        private IMem _memObjectBlue;
        private IMem _memObjectOutput;
        private Kernel _kernel;
        private int _width;
        private int _height;
        private int _numElements;

        public OpenCLImageProcessor(int width, int height)
        {
            _width = width;
            _height = height;
            _numElements = width * height;

            InitializeOpenCL();
        }

        private void InitializeOpenCL()
        {
            ErrorCode errorCode;

            // Get platform
            Platform[] platforms = Cl.GetPlatformIDs(out errorCode);
            if (errorCode != ErrorCode.Success || platforms.Length == 0)
            {
                throw new Exception("Failed to get OpenCL platforms.");
            }
            Platform platform = platforms[0];

            // Get device
            Device[] devices = Cl.GetDeviceIDs(platform, DeviceType.Gpu, out errorCode);
            if (errorCode != ErrorCode.Success || devices.Length == 0)
            {
                throw new Exception("Failed to get GPU devices.");
            }
            Device device = devices[0];

            // Create context
            _context = Cl.CreateContext(null, 1, new[] { device }, null, IntPtr.Zero, out errorCode);
            if (errorCode != ErrorCode.Success)
            {
                throw new Exception("Failed to create OpenCL context.");
            }

            // Create command queue
            _commandQueue = Cl.CreateCommandQueue(_context, device, CommandQueueProperties.None, out errorCode);
            if (errorCode != ErrorCode.Success)
            {
                throw new Exception("Failed to create command queue.");
            }

            // Create buffers
            _memObjectRed = Cl.CreateBuffer(_context, MemFlags.ReadOnly, new IntPtr(_numElements * sizeof(byte)), out errorCode);
            _memObjectGreen = Cl.CreateBuffer(_context, MemFlags.ReadOnly, new IntPtr(_numElements * sizeof(byte)), out errorCode);
            _memObjectBlue = Cl.CreateBuffer(_context, MemFlags.ReadOnly, new IntPtr(_numElements * sizeof(byte)), out errorCode);
            _memObjectOutput = Cl.CreateBuffer(_context, MemFlags.WriteOnly, new IntPtr(_numElements * 3 * sizeof(float)), out errorCode);

            // Load and build program
            string kernelSource = @"
            __kernel void vecAdd(__global const uchar* red, __global const uchar* green, __global const uchar* blue,
                                 __global float* output, int width, int height) {
                int x = get_global_id(0);
                int y = get_global_id(1);
                int index = y * width + x;
                output[index * 3] = red[index] / 255.0f;    // Normalize red
                output[index * 3 + 1] = green[index] / 255.0f; // Normalize green
                output[index * 3 + 2] = blue[index] / 255.0f;  // Normalize blue
                //print(""output[%d]=%f"",index,output[index * 3]);
            }";
            Program program = Cl.CreateProgramWithSource(_context, 1, new[] { kernelSource }, null, out errorCode);
            errorCode = Cl.BuildProgram(program, 1, new[] { device }, null, null, IntPtr.Zero);
            if (errorCode != ErrorCode.Success)
            {
                string buildLog = Cl.GetProgramBuildInfo(program, device, ProgramBuildInfo.Log, out errorCode).ToString();
                if (errorCode != ErrorCode.Success)
                {
                    throw new Exception("Failed to get build log.");
                }
                Console.WriteLine("Build Log: " + buildLog);
                throw new Exception("Failed to build OpenCL program.");
            }

            // Create kernel
            _kernel = Cl.CreateKernel(program, "vecAdd", out errorCode);
            if (errorCode != ErrorCode.Success)
            {
                throw new Exception("Failed to create kernel.");
            }

            // Set kernel arguments
            Cl.SetKernelArg(_kernel, 0, _memObjectRed);
            Cl.SetKernelArg(_kernel, 1, _memObjectGreen);
            Cl.SetKernelArg(_kernel, 2, _memObjectBlue);
            Cl.SetKernelArg(_kernel, 3, _memObjectOutput);
            Cl.SetKernelArg(_kernel, 4, _width);
            Cl.SetKernelArg(_kernel, 5, _height);
        }

        public float[,,] ProcessImage(IntPtr pointerRed, IntPtr pointerGreen, IntPtr pointerBlue)
        {
            ErrorCode errorCode;

            // Write data to buffers
            Cl.EnqueueWriteBuffer(_commandQueue, _memObjectRed, Bool.True, IntPtr.Zero, new IntPtr(_numElements * sizeof(byte)), pointerRed, 0, null, out var writeEvent);
            Cl.EnqueueWriteBuffer(_commandQueue, _memObjectGreen, Bool.True, IntPtr.Zero, new IntPtr(_numElements * sizeof(byte)), pointerGreen, 0, null, out var writeEvent1);
            Cl.EnqueueWriteBuffer(_commandQueue, _memObjectBlue, Bool.True, IntPtr.Zero, new IntPtr(_numElements * sizeof(byte)), pointerBlue, 0, null, out var writeEvent2);

            // Execute kernel
            IntPtr[] globalWorkSize = new IntPtr[] { (IntPtr)_width, (IntPtr)_height };
            IntPtr[] localWorkSize = new IntPtr[] { (IntPtr)5, (IntPtr)64 }; // Adjust based on GPU capabilities
            errorCode = Cl.EnqueueNDRangeKernel(_commandQueue, _kernel, 2, null, globalWorkSize, localWorkSize, 0, null, out var kernelEvent);
            if (errorCode != ErrorCode.Success)
            {
                throw new Exception("Failed to execute kernel.");
            }

            // Wait for kernel to finish
            Cl.WaitForEvents(1, new[] { kernelEvent });

            // Read output data
            float[,,] hostArray = new float[_height, _width, 3];
            GCHandle pinnedArray = GCHandle.Alloc(hostArray, GCHandleType.Pinned);
            errorCode = Cl.EnqueueReadBuffer(_commandQueue, _memObjectOutput, Bool.True, IntPtr.Zero, new IntPtr(_numElements * 3 * sizeof(float)), pinnedArray.AddrOfPinnedObject(), 0, null, out var readEvent);
            pinnedArray.Free();

            return hostArray;
        }

        public void Dispose()
        {
            Cl.ReleaseMemObject(_memObjectRed);
            Cl.ReleaseMemObject(_memObjectGreen);
            Cl.ReleaseMemObject(_memObjectBlue);
            Cl.ReleaseMemObject(_memObjectOutput);
            Cl.ReleaseKernel(_kernel);
            Cl.ReleaseCommandQueue(_commandQueue);
            Cl.ReleaseContext(_context);
        }

        private void ContextErrorCallback(string errInfo, IntPtr privateInfo, IntPtr cb, IntPtr userData)
        {
            Console.WriteLine("OpenCL Context Error: " + errInfo);
        }
    }
}
